package yxy.cherry.data;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import yxy.apple.util.FileUtility;
import yxy.apple.util.JSONUtility;
import yxy.apple.util.StringUtillity;

public class DataMakerJson {

	static String packageName = "yxy.cherry.data.bean";

	public void make() {
		try {
			File[] files = FileUtility.getFiles(System.getProperty("user.dir") + "/data/json/", ".json");
			for (File file : files) {
				makeFile(file, DataMaker.DIR, packageName);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	void makeFile(File file, String dir, String packageName) throws Exception {
		String filename = FileUtility.getFileNameWithoutExtension(file);// 文件名

		// bean
		{
			String path = dir + "/" + packageName.replaceAll("\\.", "/");
			File output = new File(path + "/" + filename + ".java");
			if (output.exists()) {
				output.delete();
			}
			FileUtility.create(output);

//			System.err.println("\r\nmakefile::" + filename);
			String content = assembleContent(packageName, filename, file);
//			System.err.println(content);
			FileOutputStream fos = new FileOutputStream(output);
			fos.write(content.getBytes("UTF-8"));
			fos.flush();
			fos.close();

			DataClassCheck.getInstance().inputFile(output);

			System.err.println("文件生成::" + output.getName());

		}
	}

	private String assembleContent(String packageName, String filename, File file) throws IOException {
		StringBuffer result = new StringBuffer();
		result.append(assembleHead(packageName, filename, file));
		result.append(assembleBody(packageName, filename, file));
		result.append("}");
		return result.toString();
	}

	private Map<String, JSONType> resolveFieldType(JSONArray dataArray) {
		Map<String, JSONType> map = new HashMap<>();
		for (int i = 0, size = dataArray.size(); i < size; i++) {
			JSONObject data = dataArray.getJSONObject(i);
			Set<String> keySet = data.keySet();
			for (String key : keySet) {
				JSONType type = resolveType(data, key);
				if (map.containsKey(key)) {
					if (type.ordinal() > map.get(key).ordinal()) {
						map.put(key, type);
					}
				} else {
					map.put(key, type);
				}
			}
		}
		return map;
	}

	private JSONType resolveArrayType(JSONArray dataArray, String key) {
		JSONType temptype = null;
		for (int i = 0, size = dataArray.size(); i < size; i++) {
			JSONArray array = dataArray.getJSONObject(i).getJSONArray(key);
			JSONType type = resolveType(array);
			if (temptype == null) {
				temptype = type;
			} else {
				if (type.ordinal() > temptype.ordinal()) {
					temptype = type;
				}
			}
		}
		return temptype;
	}

	private String assembleHead(String packageName, String filename, File file) {
		StringBuffer buffer = new StringBuffer();

		buffer.append("package " + packageName + ";\r\n\r\n");
		buffer.append("import yxy.cherry.data.bean.model.DataClass;\r\n");
		buffer.append("import yxy.cherry.data.bean.model.DataType;\r\n\r\n");
		buffer.append("@DataType\r\n");
		buffer.append("public class " + filename + " implements DataClass{\r\n\r\n");

		return buffer.toString();
	}

	private String assembleBody(String packageName, String filename, File file) throws IOException {
		StringBuffer bufferField = new StringBuffer();
		StringBuffer bufferFunc = new StringBuffer();

		JSONArray dataArray = JSONUtility.readArray(file);
		Map<String, JSONType> typeMap = resolveFieldType(dataArray);

		Set<String> keySet = typeMap.keySet();
		for (String key : keySet) {
			JSONType type = typeMap.get(key);
			switch (type) {
			case JSONArray:
				assembleArray(bufferField, bufferFunc, dataArray, key);
				break;
			case Boolean:
			case Double:
			case Integer:
			case Long:
			case String:
				assembleField(bufferField, bufferFunc, type, key);
				break;
			default:
				break;
			}
		}
		// code
		assembleCode(bufferFunc, filename);

		// 特殊处理
		assembleSpec(bufferFunc, filename);

		bufferField.append(bufferFunc.toString());
		return bufferField.toString();
	}

	private void assembleArray(StringBuffer bufferField, StringBuffer bufferFunc, JSONArray array, String key) {
		JSONType type = resolveArrayType(array, key);

		bufferField.append("public " + type.getTypename() + "[] " + key + ";");
		bufferField.append("\r\n\r\n");
		bufferFunc.append("public " + type.getTypename() + "[] get" + StringUtillity.capitalize(key) + "(){");
		bufferFunc.append("\r\n");
		bufferFunc.append("return " + key + ";");
		bufferFunc.append("\r\n");
		bufferFunc.append("}");
		bufferFunc.append("\r\n");
	}

	private void assembleField(StringBuffer bufferField, StringBuffer bufferFunc, JSONType type, String key) {
		bufferField.append("public " + type.getTypename() + " " + key + ";");
		bufferField.append("\r\n\r\n");
		bufferFunc.append("public " + type.getTypename() + " get" + StringUtillity.capitalize(key) + "(){");
		bufferFunc.append("\r\n");
		bufferFunc.append("return " + key + ";");
		bufferFunc.append("\r\n");
		bufferFunc.append("}");
		bufferFunc.append("\r\n");
	}

	/** 生成code */
	private void assembleCode(StringBuffer bufferFunc, String filename) {
		bufferFunc.append("@Override\r\n");
		bufferFunc.append("public String getCode(){");
		bufferFunc.append("\r\n");
		switch (filename) {
		case "heroadvanced":// 武将星级表
			bufferFunc.append("return String.format(\"%d_%d\", heroid, starlv);");
			break;
		case "plainsarena":// 中原擂台表
			bufferFunc.append("return String.valueOf(getRank());");
			break;
		case "vipdata":// vip表
			bufferFunc.append("return String.valueOf(getViplv());");
			break;
		default:
			bufferFunc.append("return String.valueOf(getId());");
			break;
		}
		bufferFunc.append("\r\n");
		bufferFunc.append("}");
		bufferFunc.append("\r\n");
	}

	/** 增加特别方法 */
	private void assembleSpec(StringBuffer bufferFunc, String filename) {
		switch (filename) {
		case "equipdata":// 装备
			bufferFunc.append("public int level(){");
			bufferFunc.append("\r\n");
			bufferFunc.append("return getQuality() * 10 + getStar();");
			break;
		default:
			return;
		}
		bufferFunc.append("\r\n");
		bufferFunc.append("}");
		bufferFunc.append("\r\n");
	}

	private JSONType resolveType(JSONObject data, String key) {
		try {
			data.getJSONArray(key);
			return JSONType.JSONArray;
		} catch (Exception e) {
		}
		try {
			long value = data.getLongValue(key);
			int ivalue = data.getIntValue(key);
			if (value != ivalue) {
				return JSONType.Long;
			}
			return JSONType.Integer;
		} catch (Exception e) {
		}
		try {
			data.getDoubleValue(key);
			return JSONType.Double;
		} catch (Exception e) {
		}
		try {
			data.getBoolean(key);
			return JSONType.Boolean;
		} catch (Exception e) {
		}
		return JSONType.String;
	}

	private JSONType resolveType(JSONArray data) {
		if (data.size() == 0) {
			return JSONType.Integer;
		}
		try {
			long value = data.getLongValue(0);
			int ivalue = data.getIntValue(0);
			if (value != ivalue) {
				return JSONType.Long;
			}
			return JSONType.Integer;
		} catch (Exception e) {
		}
		try {
			data.getDoubleValue(0);
			return JSONType.Double;
		} catch (Exception e) {
		}
		try {
			data.getBoolean(0);
			return JSONType.Boolean;
		} catch (Exception e) {
		}
		try {
			data.getString(0);
			return JSONType.String;
		} catch (Exception e) {
		}
		return JSONType.String;
	}

	enum JSONType {
		JSONArray("[]"), //
		Double("double"), //
		Integer("int"), //
		Long("long"), //
		Boolean("boolean"), //
		String("String"), //
		;

		private String typename;

		private JSONType(String typename) {
			this.typename = typename;
		}

		public String getTypename() {
			return typename;
		}
	}
}
